// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license.

#include "StandinEditorModule.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"


#include "ScopedTransaction.h"
#include "AssetRegistryModule.h"
#include "ContentBrowserModule.h"
#include "WorkspaceMenuStructure.h"
#include "WorkspaceMenuStructureModule.h"
#include "Widgets/Docking/SDockTab.h"
#include "SimplygonStyle.h"
#include "PackageTools.h"
#include "Editor/EditorPerProjectUserSettings.h"
#include "Builders/CubeBuilder.h"
#include "GameFramework/Info.h"
#include "Misc/FeedbackContext.h"
#include "PropertyEditorModule.h"

#include "Editor.h"
#include "BSPOps.h"
#include "LevelEditor.h"

#include "AssetToolsModule.h"
#include "EditorDirectories.h"
#include "ObjectTools.h"
#include "Serialization/ArchiveReplaceObjectRef.h"
#include "Simplygon/Public/SimplygonModule.h"
#include "StandInsOutliner.h"
#include "SimplygonEditorModule.h"

class FStandinEditorModule : public IStandinEditorModule
{

public:
	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
	
	virtual TSharedRef<SWidget> CreateStandinOutliner() override;
	virtual TSharedRef<SDockTab> SpawnStandinOutliner(const FSpawnTabArgs& Args) override;

private:
	void RegisterEditorTab();
	void ModulesChangedCallback(FName ModuleName, EModuleChangeReason ReasonForChange);
	bool IsSimplygonAvailable() const;
private:
	TSharedPtr<StandInsOutliner::SStandInsOutliner> StandInsOutlinerWindow;
	TSharedPtr<FUICommandList> StandInCommands;
	FDelegateHandle LevelEditorTabManagerChangedHandle;
	FDelegateHandle ModulesChangedHandle;
};

IMPLEMENT_MODULE(FStandinEditorModule, StandinEditor )
DEFINE_LOG_CATEGORY_STATIC(LogStandinEditorModule, Verbose, All);
#define LOCTEXT_NAMESPACE "StandinEditorModule"

bool FStandinEditorModule::IsSimplygonAvailable() const 
{
	if (!FModuleManager::Get().IsModuleLoaded("Simplygon"))
		return false;

	ISimplygonModule& SimplygonModule = FModuleManager::Get().LoadModuleChecked<ISimplygonModule>("Simplygon");
	return SimplygonModule.GetSDK() != nullptr;
}

void FStandinEditorModule::StartupModule()
{
	
	if (!IsSimplygonAvailable())
	{
		UE_LOG(LogStandinEditorModule, Warning, TEXT("Simplygon is not available."));
		return;
	}

	/*ISimplygonEditorModule& SimplygonEditorModule =*/ FModuleManager::LoadModuleChecked<ISimplygonEditorModule>("SimplygonEditor");

	if (FModuleManager::Get().IsModuleLoaded("LevelEditor") && FModuleManager::Get().IsModuleLoaded("LevelEditor"))
	{
		RegisterEditorTab();
	}
	else
	{
		ModulesChangedHandle = FModuleManager::Get().OnModulesChanged().AddRaw(this, &FStandinEditorModule::ModulesChangedCallback);
	}
}


void FStandinEditorModule::ShutdownModule()
{
	if (!IsSimplygonAvailable())
	{
		return;
	}

	if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
	{
		FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
		PropertyModule.UnregisterCustomPropertyTypeLayout("StandinMeshSettings");
	}

	FModuleManager::Get().OnModulesChanged().Remove(ModulesChangedHandle);

	if (LevelEditorTabManagerChangedHandle.IsValid() && FModuleManager::Get().IsModuleLoaded("LevelEditor"))
	{
		FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
		LevelEditorModule.OnTabManagerChanged().Remove(LevelEditorTabManagerChangedHandle);
	}
}

TSharedRef<SDockTab> FStandinEditorModule::SpawnStandinOutliner(const FSpawnTabArgs& /*Args*/)
{

	return SNew(SDockTab)
		.Icon(FSimplygonStyle::Get().GetBrush("Simplygon.Tabs.StandIn"))
		.Label(NSLOCTEXT("LevelEditor", "StandInTabTitle", "Stand-ins Outliner"))
		[
			SNew(SBorder)
			.Padding(FMargin(0.0f))
		.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
		[
			CreateStandinOutliner()
		]
		];
}

void FStandinEditorModule::RegisterEditorTab()
{
	FLevelEditorModule& LevelEditorModule = FModuleManager::Get().LoadModuleChecked<FLevelEditorModule>("LevelEditor");

	LevelEditorTabManagerChangedHandle = LevelEditorModule.OnTabManagerChanged().AddLambda([this]()
		{
			FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>("LevelEditor");
			TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();

			const FSlateIcon ReplacementIcon(FSimplygonStyle::Get().GetStyleSetName(), "Simplygon.Tabs.StandIn");
			LevelEditorModule.GetLevelEditorTabManager()->RegisterTabSpawner("SimplygonStandInsOutliner", FOnSpawnTab::CreateRaw(this, &FStandinEditorModule::SpawnStandinOutliner))
				.SetDisplayName(NSLOCTEXT("LevelEditorTabs", "SimplygonStandInsOutliner", "Standin Outliner"))
				.SetTooltipText(NSLOCTEXT("LevelEditorTabs", "SimplygonStandInsOutlinerToolTip", "Open standin outLiner."))
				.SetGroup(WorkspaceMenu::GetMenuStructure().GetLevelEditorCategory())
				.SetIcon(ReplacementIcon);
		});
}

void FStandinEditorModule::ModulesChangedCallback(FName ModuleName, EModuleChangeReason ReasonForChange)
{
	if (ReasonForChange == EModuleChangeReason::ModuleLoaded && ModuleName == "LevelEditor")
	{
		RegisterEditorTab();
	}
}

TSharedRef<SWidget> FStandinEditorModule::CreateStandinOutliner()
{
	SAssignNew(StandInsOutlinerWindow, StandInsOutliner::SStandInsOutliner);
	return StandInsOutlinerWindow->AsShared();
}


#undef LOCTEXT_NAMESPACE
